package com.server.rule;


import java.util.ArrayList;
import java.util.List;

import org.jdom.Element;



import com.server.rule.data.Data;
import com.server.rule.component.BaseComponent;
import com.server.rule.component.DecisionHandler;
import com.server.rule.component.RuleComponent;
import com.server.rule.component.RuleDecision;
import com.server.rule.data.ExceptionTypeData;
/**
 * Classe regroupant tout les éléments du système de gestion : 
 * @author queyroi
 *
 */
public class DecisionMaker {
	
	/**
	 * Racine de l'arbre de Decision (implicitement de type {@link BaseComponent})
	 */
	private RuleComponent baseComponent;
	private Data dataStructure;
	private String label;
	private String cible;
	
	
	public DecisionMaker() {
		baseComponent = new BaseComponent();
		dataStructure = new Data();
		label = "Label";
		cible = "Cible";
	}
	
	public DecisionMaker(String label,String cible,RuleComponent baseComponent,Data dataStructure) {
		this.label=label;
		this.cible = cible;
		this.baseComponent = baseComponent;
		this.dataStructure = dataStructure;
	}
	/**
	 * Appel d'un parcours de l'arbre
	 * Verifie les variables en entree
	 * @param entryData les donnes utilisé par le systeme
	 * @param ruleDecision Decision par defaut (référence modifiée si une decision est atteinte)
	 * @return La decision atteinte ou celle en defaut placé en parametre
	 * @throws ExceptionTypeData
	 * @throws NullPointerException
	 */
	public List<RuleDecision> operate(Data entryData,RuleDecision ruleDecision) throws ExceptionTypeData,NullPointerException{
		dataStructure.copyParam(entryData);
		dataStructure.verify(entryData,getUsedVar());
		allVarAvailable(entryData);
		DecisionHandler handler = new DecisionHandler();
		handler.addDecision(ruleDecision);
		baseComponent.operate(entryData, handler);	
		return handler.getFinalDecision();
	}
	/**
	 * @param baseComponent the baseComponent to set
	 */
	public void setBaseComponent(RuleComponent baseComponent) {
		this.baseComponent = baseComponent;
	}
	/**
	 * @return the baseComponent
	 */
	public RuleComponent getBaseComponent() {
		return baseComponent;
	}
	/**
	 * @param dataStructure the dataStructure to set
	 */
	public void setDataStructure(Data dataStructure) {
		this.dataStructure = dataStructure;
	}
	/**
	 * @return the dataStructure
	 */
	public Data getDataStructure() {
		return dataStructure;
	}
	/**
	 * @param label the label to set
	 */
	public void setLabel(String label) {
		this.label = label;
	}
	/**
	 * @return the label
	 */
	public String getLabel() {
		return label;
	}
	/**
	 * Appel de la methode hasDecision() de {@link BaseComponent}
	 * @return
	 */
	public boolean hasDecision(){
		return baseComponent.hasDecision();
	}
	
	/**
	 * Verifie que les donnees {@link Data} correspondent à une structure de donnees 
	 * @return
	 */
	public boolean verifyDataIsStructure(){
		return dataStructure.isDataStructure();
	}
	
	/**
	 * Generation de l' {@link Element} xml represantant le systeme
	 * @return
	 */
	public Element getXMLElement(){		
		
		Element xmlElement = new Element("DecisionMaker");		
		xmlElement.setAttribute("label", label);		
		xmlElement.setAttribute("cible", cible);
		xmlElement.addContent(dataStructure.getXMLElement());
		xmlElement.addContent(baseComponent.getXMLElement());		
		return xmlElement;
	}
	/**
	 * Generation le systeme à partir  de l'{@link Element} xml 
	 * @return
	 */
	public void generateFromXML(Element xmlElement){
		label = xmlElement.getAttributeValue("label");		
		cible = xmlElement.getAttributeValue("cible");		
		dataStructure = new Data();		
		dataStructure.generateFromXML(xmlElement.getChild("DecisionMakerData"));
		baseComponent = new BaseComponent();
		baseComponent.generateFromXML(xmlElement.getChild("BaseComponent"));
	}
	
	
	/**
	 * Methode permettant de recupérer les donnes utilisé par le système	
	 * @return List des label des donnes utilisés par le système
	 */
	public List<String> getUsedVar(){
		List<String> listeVar = new ArrayList<String>();
		baseComponent.getUsedVar(listeVar);
		return listeVar;
	}
	
	/**
	 * Verifie que tout les donnes sont disponible dans les donnees en entree
	 * @param entryData les donnes en entree
	 */
	public void allVarAvailable(Data entryData){		
		for(String s : getUsedVar()){
			if(!entryData.getLabel().contains(s)) throw new NullPointerException(s+"n'est pas present dans la structure de donnes");
		}		
	}

	/**
	 * @param cible the cible to set
	 */
	public void setCible(String cible) {
		this.cible = cible;
	}

	/**
	 * @return the cible
	 */
	public String getCible() {
		return cible;
	}
}
